using System;
using System.Collections.Generic;
using System.Text;

namespace SSOConfig
{
    /// <summary>
    /// Represents a field in an SSO config store
    /// </summary>
    public partial class Field
    {
        #region Private instance fields

        private static List<Type> validFieldTypes;
        private static string validFieldTypeNames;

        #endregion

        #region Public instance properties

        /// <summary>
        /// Returns a list of field types valid for storing in SSO
        /// </summary>
        public static List<Type> ValidFieldTypes
        {
            get
            {
                if (validFieldTypes == null)
                {
                    validFieldTypes = new List<Type>();
                    //SSO only allows four types:
                    validFieldTypes.Add(typeof(System.String));
                    validFieldTypes.Add(typeof(System.Int32));
                    validFieldTypes.Add(typeof(System.UInt32));
                    validFieldTypes.Add(typeof(System.Boolean));
                    //- see http://blogs.msdn.com/kevin_michael_schultz/archive/2006/12/14/eat-my-rough-draft-punk.aspx
                }
                return validFieldTypes;
            }
        }

        /// <summary>
        /// Returns string representation of types valid for storing in SSO
        /// </summary>
        public static string ValidFieldTypeNames
        {
            get
            {
                if (validFieldTypeNames == null)
                {
                    StringBuilder builder = new StringBuilder();
                    foreach (Type type in validFieldTypes)
                    {
                        builder.AppendFormat("{0}, ", type.Name);
                    }
                    validFieldTypeNames = builder.ToString().TrimEnd(", ".ToCharArray());
                }
                return validFieldTypeNames;
            }
        }

        /// <summary>
        /// Gets/sets the field value
        /// </summary>
        public object ValueObject
        {
            get
            {
                return Convert.ChangeType(this.Value, System.Type.GetType(this.Type));
            }
            set
            {
                this.Value = value.ToString();
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Default constructor
        /// </summary>
        public Field() { }

        /// <summary>
        /// Constructor with known state
        /// </summary>
        /// <param name="name">Field name</param>
        /// <param name="masked">Whether the field is masked by SSO</param>
        /// <param name="type">Field type</param>
        /// <param name="value">Initial field value</param>
        public Field(string name, bool masked, string type, string value)
        {
            this.nameField = name;
            this.maskedField = masked;
            this.typeField = type;
            this.valueField = value;
        }

        #endregion

        #region Public instance methods

        /// <summary>
        /// Returns the field value
        /// </summary>
        /// <returns>Field value</returns>
        public object GetValue()
        {
            return Convert.ChangeType(this.Value, System.Type.GetType(this.Type));
        }

        /// <summary>
        /// Validates that the field is of a valid type for SSO, and that the
        /// value of the field matches the expected type
        /// </summary>
        public void Validate()
        {
            //validate the value is of the correct type:
            Type fieldType = System.Type.GetType(this.Type);
            //check the type is valid for SSO:
            if (!Field.ValidFieldTypes.Contains(fieldType))
            {
                throw new ApplicationException(string.Format("Field type: {0} not valid for SSO. Valid types: {1}", this.Type, Field.ValidFieldTypeNames));
            }
            try
            {
                Convert.ChangeType(this.Value, fieldType);
            }
            catch (Exception ex)
            {
                throw new ApplicationException(string.Format("Field value: {0} not valid for type: {1}", this.Value, this.Type), ex);
            }
        }

        #endregion
    }
}
